
            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <title>Kubernetes核心指标监控——Metrics Server详解</title>
            </head>
            <body>
            <a href="https://andyoung.blog.csdn.net">原作者博客</a>
            <div id="content_views" class="markdown_views prism-atom-one-light">
                    <svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
                        <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
                    </svg>
                    <h3><a id="1_0"></a>1、概述</h3> 
<p>从Kubernetes v1.8 开始，资源使用情况的监控可以通过 Metrics API的形式获取，例如容器CPU和内存使用率。这些度量可以由用户直接访问（例如，通过使用kubectl top命令），或者由集群中的控制器（例如，Horizontal Pod Autoscaler）使用来进行决策，具体的组件为Metrics Server，用来替换之前的heapster，heapster从1.11开始逐渐被废弃。</p> 
<p>Metrics-Server是集群核心监控数据的聚合器。通俗地说，它存储了集群中各节点的监控数据，并且提供了API以供分析和使用。Metrics-Server作为一个 Deployment对象默认部署在Kubernetes集群中。不过准确地说，它是Deployment，Service，ClusterRole，ClusterRoleBinding，APIService，RoleBinding等资源对象的综合体。</p> 
<p>项目地址：https://github.com/kubernetes-sigs/metrics-server ,目前稳定版本是v0.6.2。</p> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/5388795ad470fee7e11a289dcae0ba87.png" alt="img"></p> 
<p><strong>metric-server主要用来通过aggregate api向其它组件（<code>kube-scheduler、</code>HorizontalPodAutoscaler、Kubernetes集群客户端等）提供集群中的pod和node的cpu和memory的监控指标，弹性伸缩中的podautoscaler就是通过调用这个接口来查看pod的当前资源使用量来进行pod的扩缩容的。</strong></p> 
<p>需要注意的是：</p> 
<ul><li>metric-server提供的是实时的指标（实际是最近一次采集的数据，保存在内存中），并没有数据库来存储</li><li>这些数据指标并非由metric-server本身采集，而是由每个节点上的<strong>cadvisor</strong>采集，metric-server只是发请求给cadvisor并将metric格式的数据转换成aggregate api</li><li>由于需要通过aggregate api来提供接口，需要集群中的kube-apiserver开启该功能（开启方法可以参考官方社区的文档）</li></ul> 
<h3><a id="2Metrics_Server_18"></a>2、部署Metrics Server</h3> 
<h4><a id="21_Metrics_Server_20"></a>2.1 下载并部署Metrics Server</h4> 
<p>下载部署清单：</p> 
<pre><code>wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.2/components.yaml
</code></pre> 
<p>修改部署清单内容：</p> 
<pre><code>apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    k8s-app: metrics-server
    rbac.authorization.k8s.io/aggregate-to-admin: "true"
    rbac.authorization.k8s.io/aggregate-to-edit: "true"
    rbac.authorization.k8s.io/aggregate-to-view: "true"
  name: system:aggregated-metrics-reader
rules:
- apiGroups:
  - metrics.k8s.io
  resources:
  - pods
  - nodes
  verbs:
  - get
  - list
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    k8s-app: metrics-server
  name: system:metrics-server
rules:
- apiGroups:
  - ""
  resources:
  - nodes/metrics
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - pods
  - nodes
  verbs:
  - get
  - list
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server-auth-reader
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: extension-apiserver-authentication-reader
subjects:
- kind: ServiceAccount
  name: metrics-server
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server:system:auth-delegator
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:auth-delegator
subjects:
- kind: ServiceAccount
  name: metrics-server
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    k8s-app: metrics-server
  name: system:metrics-server
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:metrics-server
subjects:
- kind: ServiceAccount
  name: metrics-server
  namespace: kube-system
---
apiVersion: v1
kind: Service
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server
  namespace: kube-system
spec:
  ports:
  - name: https
    port: 443
    protocol: TCP
    targetPort: https
  selector:
    k8s-app: metrics-server
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server
  namespace: kube-system
spec:
  selector:
    matchLabels:
      k8s-app: metrics-server
  strategy:
    rollingUpdate:
      maxUnavailable: 0
  template:
    metadata:
      labels:
        k8s-app: metrics-server
    spec:
      containers:
      - args:
        - --cert-dir=/tmp
        - --secure-port=4443
        - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
        - --kubelet-use-node-status-port
        - --metric-resolution=15s
        - --kubelet-insecure-tls
        image: k8s.gcr.io/metrics-server/metrics-server:v0.6.2
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /livez
            port: https
            scheme: HTTPS
          periodSeconds: 10
        name: metrics-server
        ports:
        - containerPort: 4443
          name: https
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /readyz
            port: https
            scheme: HTTPS
          initialDelaySeconds: 20
          periodSeconds: 10
        resources:
          requests:
            cpu: 100m
            memory: 200Mi
        securityContext:
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          runAsNonRoot: true
          runAsUser: 1000
        volumeMounts:
        - mountPath: /tmp
          name: tmp-dir
      nodeSelector:
        kubernetes.io/os: linux
      priorityClassName: system-cluster-critical
      serviceAccountName: metrics-server
      volumes:
      - emptyDir: {}
        name: tmp-dir
---
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
  labels:
    k8s-app: metrics-server
  name: v1beta1.metrics.k8s.io
spec:
  group: metrics.k8s.io
  groupPriorityMinimum: 100
  insecureSkipTLSVerify: true
  service:
    name: metrics-server
    namespace: kube-system
  version: v1beta1
  versionPriority: 100
</code></pre> 
<p>在deploy中，spec.template.containers.args字段中加上<code>--kubelet-insecure-tls</code>选项，表示不验证客户端证书；上述清单主要用deploy控制器将metrics server运行为一个pod，然后授权metrics-server用户能够对pod/node资源进行只读权限；<strong>然后把metrics.k8s.io/v1beta1注册到原生apiserver上，让其客户端访问metrics.k8s.io下的资源能够被路由至metrics-server这个服务上进行响应；</strong></p> 
<blockquote> 
 <p>镜像被墙怎么办？</p> 
 <p>修改镜像 <code>k8s.gcr.io/metrics-server/metrics-server:v0.6.2</code> -&gt; <code>admin4j/metrics-server:v0.6.2</code></p> 
 <p>或者参考 <a href="https://blog.csdn.net/agonie201218/article/details/128298327">k8s镜像下载不下来？利用 github Action 自己动手一次性解决难题，丰衣足食</a></p> 
</blockquote> 
<p>应用资源清单：</p> 
<pre><code>[root@master1 metrics-server]# kubectl apply -f components.yaml
serviceaccount/metrics-server created
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
clusterrole.rbac.authorization.k8s.io/system:metrics-server created
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created
service/metrics-server created
deployment.apps/metrics-server created
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
</code></pre> 
<h4><a id="22_Metrics_Server_253"></a>2.2 验证Metrics Server组件部署成功</h4> 
<p>（1）查看原生apiserver是否有metrics.k8s.io/v1beta1</p> 
<pre><code>[root@master1 metrics-server]# kubectl api-versions|grep metrics
metrics.k8s.io/v1beta1
</code></pre> 
<p>可以看到metrics.k8s.io/v1beta1群组已经注册到原生apiserver上。</p> 
<p>（2）查看metrics server pod是否运行正常</p> 
<pre><code>[root@master1 ~]# kubectl get pods -n=kube-system |grep metrics
metrics-server-855cc6b9d-g6xsf  1/1   Running  0     18h
</code></pre> 
<p>可以看到对应pod已经正常运行，接着查看pod日志，只要metrics server pod没有出现错误日志，或者无法注册等信息，就表示pod里的容器运行正常。</p> 
<p>（3）使用kubectl top 命令查看pod的cpu ，内存占比，看看对应命令是否可以正常执行，如果Metrics Server服务有异常的话会报Error from server (ServiceUnavailable): the server is currently unable to handle the request (get nodes.metrics.k8s.io)错误。</p> 
<pre><code>[root@master1 ~]# kubectl top nodes
NAME      CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%  
master1   272m         3%     4272Mi          29%      
node1     384m         5%     9265Mi          30%      
node2     421m         5%     14476Mi         48%  
</code></pre> 
<p>可以看到kubectl top命令可以正常执行，说明metrics server 部署成功没有问题。</p> 
<h3><a id="3_285"></a>3、原理</h3> 
<p>Metrics server定时从Kubelet的Summary API(类似<code>/ap1/v1/nodes/nodename/stats/summary</code>)采集指标信息，这些聚合过的数据将存储在内存中，且以metric-api的形式暴露出去。</p> 
<p>Metrics server复用了api-server的库来实现自己的功能，比如鉴权、版本等，为了实现将<strong>数据存放在内存中</strong>吗，去掉了默认的etcd存储，引入了内存存储（即实现<a href="https://github.com/kubernetes/apiserver/blob/master/pkg/registry/rest/rest.go">Storage interface</a>)。</p> 
<p>因为存放在内存中，因此监控数据是没有持久化的，可以通过第三方存储来拓展。</p> 
<p>来看下Metrics-Server的架构：</p> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/1fb68b622a874e2bd921bcd03c7413f9.png" alt="Metrics-Server的架构"></p> 
<p>从 Kubelet、cAdvisor 等获取度量数据，再由metrics-server提供给 Dashboard、HPA 控制器等使用。本质上<code>metrics-server</code>相当于做了一次数据的转换，把<code>cadvisor</code>格式的数据转换成了kubernetes的<code>api</code>的<code>json</code>格式。由此我们不难猜测，<code>metrics-server</code>的代码中必然存在这种先从metric中获取接口中的所有信息，再解析出其中的数据的过程。我们给<code>metric-server</code>发送请求时，<code>metrics-server</code>中已经定期从中<code>cadvisor</code>获取好数据了，当请求发过来时直接返回缓存中的数据。</p> 
<h3><a id="4_299"></a>4、如何获取监控数据</h3> 
<p>Metrics-Server通过<code>kubelet</code>获取监控数据。</p> 
<p>在1.7版本之前，k8s在每个节点都安装了一个叫做<code>cAdvisor</code>的程序，负责获取节点和容器的CPU，内存等数据；而在1.7版本及之后，k8s将cAdvisor精简化内置于kubelet中，因此可直接从kubelet中获取数据。</p> 
<h3><a id="5_305"></a>5、如何提供监控数据</h3> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/b69ff5416024f510faad3061e5fc04da.png" alt="img"></p> 
<p>Metrics-Server通过<code>metrics API</code>提供监控数据。</p> 
<p>先说下API聚合机制，API聚合机制是kubernetes 1.7版本引入的特性，能将用户扩展的API注册至API Server上。</p> 
<p>API Server在此之前只提供kubernetes资源对象的API，包括资源对象的增删查改功能。有了API聚合机制之后，用户可以发布自己的API，而Metrics-Server用到的<code>metrics API</code>和<code>custom metrics API</code>均属于API聚合机制的应用。</p> 
<p>用户可通过配置APIService资源对象以使用API聚合机制，如下是metrics API的配置文件：</p> 
<pre><code>apiVersion: apiregistration.k8s.io/v1beta1
kind: APIService
metadata:
  name: v1beta1.metrics.k8s.io
spec:
  service:
    name: metrics-server
    namespace: kube-system
  group: metrics.k8s.io
  version: v1beta1
  insecureSkipTLSVerify: true
  groupPriorityMinimum: 100
  versionPriority: 100
</code></pre> 
<p>如上，APIService提供了一个名为<code>v1beta1.metrics.k8s.io</code>的API，并绑定至一个名为<code>metrics-server</code>的Service资源对象。</p> 
<p>可以通过<code>kubectl get apiservices</code>命令查询集群中的APIService。</p> 
<p>因此，访问Metrics-Server的方式如下：</p> 
<pre><code>/apis/metrics.k8s.io/v1beta1  ---&gt;   metrics-server.kube-system.svc  ---&gt;   x.x.x.x
 
+---------+       +-----------+                   +------------------------+        +-----------------------------+
| 发起请求 +-----&gt;+ API Server +-----------------&gt;+ Service：metrics-server +--------&gt;+ Pod：metrics-server-xxx-xxx |
</code></pre> 
<p>有了访问Metrics-Server的方式，HPA，<code>kubectl top</code>等对象就可以正常工作了。</p> 
<h3><a id="6_348"></a>6、总结</h3> 
<p>kubernetes的新监控体系中，metrics-server属于Core metrics(核心指标)，提供API metrics.k8s.io，仅提供Node和Pod的CPU和内存使用情况。而其他Custom Metrics(自定义指标)由Prometheus等组件来完成，后续文章将对自定义指标进行解析。</p> 
<p>参考：<a href="https://staight.github.io/2019/09/12/metrics-server%E6%B5%85%E8%B0%88/" rel="nofollow">https://staight.github.io/2019/09/12/metrics-server%E6%B5%85%E8%B0%88/</a></p> 
<p>参考：http://yost.top/2020/05/17/about-metric-server/</p> 
<p>参考：https://yasongxu.gitbook.io/container-monitor/yi-.-kai-yuan-fang-an/di-1-zhang-cai-ji/metrics-server</p>
                </div>
            </body>
            </html>
            